package com.zjl.media.netty;

import com.zjl.media.config.properties.MediaProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.unix.PreferredDirectByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

/**
 * @author linfuxin Created on 2022-03-02 08:53:24
 */
@Order(value = Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class NettyServer implements InitializingBean, CommandLineRunner {
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ServerBootstrap serverBootstrap;

    private final MediaProperties properties;
    private final MediaServerInitializer nettyServerInitializer;

    public NettyServer(MediaProperties properties, MediaServerInitializer nettyServerInitializer) {
        this.properties = properties;
        this.nettyServerInitializer = nettyServerInitializer;

    }

    @Override
    public void afterPropertiesSet() {
        //创建主线程组，接收请求
        bossGroup = new NioEventLoopGroup();
        //创建从线程组，处理主线程组分配下来的io操作
        workerGroup = new NioEventLoopGroup();
        //创建netty服务器
        serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(nettyServerInitializer)
                .localAddress(properties.getWebSocket().getPort())
                .option(ChannelOption.SO_BACKLOG, 128)
                //首选直接内存
                .option(ChannelOption.ALLOCATOR, PreferredDirectByteBufAllocator.DEFAULT)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.SO_RCVBUF, 128 * 1024)
                .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)
                .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024 / 2, 1024 * 1024));
    }

    @Override
    public void run(String... args) {
        log.info("启动mediaServer!端口号:{}", properties.getWebSocket().getPort());
        start();
    }

    private void start() {
        try {
            //启动server
            ChannelFuture channelFuture = serverBootstrap.bind(properties.getWebSocket().getPort()).sync();
            //监听关闭channel
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("netty异常!", e);
        } finally {
            bossGroup.shutdownGracefully();//关闭主线程
            workerGroup.shutdownGracefully();//关闭从线程
        }
    }
}
